package cn.xiaobai.j2exe.domain;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.FileUtil;
import cn.xiaobai.j2exe.consts.SysType;
import cn.xiaobai.j2exe.utils.FileUtils;
import cn.xiaobai.j2exe.utils.SysUtils;
import com.alibaba.fastjson2.annotation.JSONField;
import com.badlogicgames.packr.PackrConfig;

import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 转换配置, 记录jar 转换 exe 填写的数据
 *
 * @Author yangdaji
 * @Date 2023/12/27
 * @PackageName cn.xiaobai.j2exe.domain
 * @ClassName ConvertConfig
 */
public class ConvertConfig implements Serializable {


    /**
     * 平台选择  windows64 , linux64, mac
     */
    private SysType platform;

    /**
     * jdk 路径, 可以是目录, zip,tar.gz,或者 url
     */
    private String jdk;

    /**
     * 执行名称
     */
    private String executable;

    /**
     * 依赖路径
     */
    private transient File jarPath;

    /**
     * 依赖路径
     */
    private List<String> classpath = new ArrayList<>();

    /**
     * 移除依赖
     */
    @JSONField(name = "removeLib")
    private List<String> removePlatformLibs = new ArrayList<>();
    /**
     * 主程序入口
     */
    @JSONField(name = "mainclass")
    private String mainClass;
    /**
     * jvm 参数
     */
    @JSONField(name = "vmargs")
    private List<String> vmArgs = new ArrayList<>();
    /**
     * 资源文件
     */
    private List<File> resources = new ArrayList<>();
    /**
     * 输出目录, 目录必须为空
     */
    @JSONField(name = "output")
    private File outDir;
    /**
     * 图标, 目前只支持 mac, 后面测试看是否可以通过程序去修改
     */
    @JSONField(name = "icon")
    private File iconResource;

    public void verifyConf() throws IOException {
        //  exe
        validate(platform, "platform");
        validate(executable, "executable name");
        validate(outDir, "output folder");

        // app
        validate(mainClass, "main class");
        validate(jarPath, "jar path");
        validate(classpath, "class path");

        // jvm selection
        validate(jdk, "JDK");
    }

    private <T> void validate(T parameter, String name) throws IOException {
        boolean isNull = false;
        if (parameter == null) {
            isNull = true;
        }
        if (parameter instanceof Collection collection) {
            if (CollectionUtil.isEmpty(collection)) {
                isNull = true;
            }
        }

        if (isNull) {
            throw new IOException("Required fields (" + name + ") Cannot be null");
        }

    }

    public PackrConfig toPackageConf() {
        final PackrConfig packrConfig = new PackrConfig();
        packrConfig.platform = getPlatform();
        packrConfig.jdk = getJdk();
        packrConfig.executable = getExecutable();
        packrConfig.classpath = getClasspath();
        packrConfig.mainClass = getMainClass();
        packrConfig.vmArgs = getVmArgs();
        packrConfig.resources = getResources();
        packrConfig.outDir = getOutDir();
        return packrConfig;
    }

    public void copyData(ConvertConfig source) {
        BeanUtil.copyProperties(source, this);
    }

    public void addClassPath(String... classPath) {
        List<String> classpathList = getClasspath();
        List<String> classPaths = List.of(classPath);
        if (classpathList != null && !new HashSet<>(classpathList).containsAll(classPaths)) {
            classpathList.addAll(classPaths);
        } else {
            setClasspath(classPaths);
        }
    }

    public void addRemoveLib(String... removeLib) {
        List<String> removePlatformLibs = getRemovePlatformLibs();
        List<String> removeLibs = List.of(removeLib);
        if (removePlatformLibs != null && !new HashSet<>(removePlatformLibs).containsAll(removeLibs)) {
            removePlatformLibs.addAll(removeLibs);
        } else {
            setRemovePlatformLibs(removeLibs);
        }
    }

    public void addVmArgs(String... vmArgs) {
        List<String> vmArgsList = getVmArgs();
        List<String> vmArgss = List.of(vmArgs);
        if (vmArgsList != null && !new HashSet<>(vmArgsList).containsAll(vmArgss)) {
            vmArgsList.addAll(vmArgss);
        } else {
            setVmArgs(vmArgss);
        }
    }

    public void addResources(File... resource) {
        List<File> resourcesList = getResources();
        List<File> resources = List.of(resource);
        if (resourcesList != null && !new HashSet<>(resourcesList).containsAll(resources)) {
            resourcesList.addAll(resources);
        } else {
            setResources(resources);
        }
    }

    public ConvertConfig() {
    }


    public ConvertConfig(SysType platform, String jdk, String executable,
                         List<String> classpath, List<String> removePlatformLibs,
                         String mainClass, List<String> vmArgs, List<File> resources,
                         File outDir, File iconResource) {
        this.platform = platform;
        this.jdk = jdk;
        this.executable = executable;
        this.classpath = classpath;
        this.removePlatformLibs = removePlatformLibs;
        this.mainClass = mainClass;
        this.vmArgs = vmArgs;
        this.resources = resources;
        this.outDir = outDir;
        this.iconResource = iconResource;
    }

    public PackrConfig.Platform getPlatform() {
        if (platform != null) {
            return SysType.toType(platform.getDesc());
        }
        return null;
    }

    public void setPlatform(String platform) {
        if (this.platform == null ||
                (platform != null &&
                        !Objects.equals(this.platform.getDesc(), platform))) {
            this.platform = SysType.byDesc(platform);
        }
    }

    public String getJdk() {
        return jdk;
    }

    public void setJdk(String jdk) {
        if (!Objects.equals(this.jdk, jdk)) {
            this.jdk = jdk;
        }
    }

    public String getExecutable() {
        return executable;
    }

    public void setExecutable(String executable) {
        if (!Objects.equals(this.executable, executable)) {
            this.executable = executable;
        }
    }

    public File getJarPath() {
        return jarPath;
    }

    public void setJarPath(File jarPath) {
        this.jarPath = jarPath;
    }

    public List<String> getClasspath() {
        return classpath;
    }

    public void setClasspath(List<String> classpath) {
        this.classpath = classpath.stream().map(FileUtils::reversPath).collect(Collectors.toList());
    }

    public List<String> getRemovePlatformLibs() {
        return removePlatformLibs;
    }

    public void setRemovePlatformLibs(List<String> removePlatformLibs) {
        this.removePlatformLibs = removePlatformLibs.stream()
                .map(FileUtils::reversPath).collect(Collectors.toList());
    }

    public String getMainClass() {
        return mainClass;
    }

    public void setMainClass(String mainClass) {
        this.mainClass = mainClass;
    }

    public List<String> getVmArgs() {
        return vmArgs;
    }

    public void setVmArgs(List<String> vmArgs) {
        this.vmArgs = vmArgs;
    }

    public List<File> getResources() {
        return resources;
    }

    public void setResources(List<File> resources) {
        this.resources = resources;
    }

    public File getOutDir() {
        return outDir;
    }

    public void setOutDir(File outDir) {
        if (!Objects.equals(this.outDir, outDir)) {
            this.outDir = outDir;
        }
    }

    public File getIconResource() {
        return iconResource;
    }

    public void setIconResource(File iconResource) {
        this.iconResource = iconResource;
    }
}
